package com.smart.community.commons.log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import com.smart.community.commons.exception.AuthenticationException;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.exception.DataAlreadyExistsException;
import com.smart.community.commons.exception.DataNotFoundException;
import com.smart.community.commons.exception.ModuleBusinessException;
import com.smart.community.commons.exception.SystemException;

import lombok.extern.slf4j.Slf4j;

/**
 * 性能日志切面 用于记录方法执行时间，监控系统性能
 * 
 * @author Wu.Liang
 * @since 2024-12-19
 * @version 1.0.0
 */
@Slf4j
@Aspect
@Component
public class PerformanceLogAspect {

	/**
	 * 性能监控切点 监控所有Controller层方法的执行时间
	 * 
	 * @param joinPoint 连接点
	 * @return 方法执行结果
	 * @throws Throwable 异常
	 */
	@Around("execution(* com.smart.community..*.controller.*.*(..))")
	public Object logPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
		long startTime = System.currentTimeMillis();
		String methodName = joinPoint.getSignature().getName();
		String className = joinPoint.getTarget().getClass().getSimpleName();

		try {
			Object result = joinPoint.proceed();
			long endTime = System.currentTimeMillis();
			long executionTime = endTime - startTime;

			// 记录性能日志
			logPerformanceInfo(className, methodName, executionTime);
			return result;
		} catch (Throwable e) {
			long endTime = System.currentTimeMillis();
			long executionTime = endTime - startTime;
			
			// 根据异常类型决定日志级别和内容
			logException(className, methodName, executionTime, e);
			throw e;
		}
	}
	
	/**
	 * 记录性能信息
	 * 
	 * @param className 类名
	 * @param methodName 方法名
	 * @param executionTime 执行时间
	 */
	private void logPerformanceInfo(String className, String methodName, long executionTime) {
		if (executionTime > 1000) {
			log.warn("⏱️ 方法执行时间较长: {}.{} - {}ms", className, methodName, executionTime);
		} else if (executionTime > 500) {
			log.info("⏱️ 方法执行时间: {}.{} - {}ms", className, methodName, executionTime);
		} else {
			log.debug("⏱️ 方法执行时间: {}.{} - {}ms", className, methodName, executionTime);
		}
	}
	
	/**
	 * 记录异常信息
	 * 根据《业务异常日志处理规范.md》权威标准：
	 * - 业务异常：只记录异常消息，不打印堆栈信息
	 * - 系统异常：记录异常消息和完整堆栈信息
	 * 
	 * @param className 类名
	 * @param methodName 方法名
	 * @param executionTime 执行时间
	 * @param e 异常
	 */
	private void logException(String className, String methodName, long executionTime, Throwable e) {
		// 判断是否为业务异常
		if (isBusinessException(e)) {
			// 业务异常：只记录异常消息，不打印堆栈
			log.warn("❌ 业务异常: {}.{} - {}ms - {}", className, methodName, executionTime, e.getMessage());
		} else {
			// 系统异常：记录异常消息和完整堆栈
			log.error("❌ 系统异常: {}.{} - {}ms", className, methodName, executionTime, e);
		}
	}
	
	/**
	 * 判断是否为业务异常
	 * 根据《业务异常日志处理规范.md》权威标准定义
	 * 
	 * @param e 异常
	 * @return 是否为业务异常
	 */
	private boolean isBusinessException(Throwable e) {
		return e instanceof AuthenticationException ||
			   e instanceof BusinessException ||
			   e instanceof DataAlreadyExistsException ||
			   e instanceof DataNotFoundException ||
			   e instanceof ModuleBusinessException ||
			   e instanceof SystemException;
	}
}
